<template>
  <div ref="animatedElement" :style="computedStyle">
    <slot></slot>
  </div>
</template>
  


  <script>
/**
   * 
   * <div class="level-slide">
          <slideIn
            v-for="(s, idx) in list"
            :key="idx"
            :duration="500 * idx + 500"
          >
            <p>{{ idx }} - slideIn</p>
          </slideIn>
        </div>
const list = Array(100).fill(10); // 用 10 填充数组

   * 
   * 
   */
export default {
  name: "slideIn",
  props: {
    duration: {
      // 动画持续时间
      type: Number,
      default: 1000,
    },
    easing: {
      // 动画缓动效果
      type: String,
      default: "ease",
    },
    distance: {
      // 动画距离
      type: Number,
      default: 100,
    },
  },
  data() {
    return {
      hasAnimated: false, // 是否已经动画过
    };
  },
  computed: {
    computedStyle() {
      return {
        opacity: this.hasAnimated ? 1 : 0,
        transform: this.hasAnimated
          ? "translateY(0)"
          : `translateY(${this.distance}px)`,
        transition: `transform ${this.duration}ms ${this.easing}, opacity ${this.duration}ms ${this.easing}`,
      };
    },
  },
  mounted() {
    if (typeof window !== "undefined" && "IntersectionObserver" in window) {
      // 检测是否支持IntersectionObserver
      this.createObserver(); // 创建IntersectionObserver
    } else {
      // 如果不支持IntersectionObserver，则使用scroll事件来实现动画
      this.observeScroll();
    }
  },
  methods: {
    createObserver() {
      const observer = new IntersectionObserver(
        (entries) => {
          // IntersectionObserver回调函数
          entries.forEach((entry) => {
            // 遍历每个观察目标
            if (entry.isIntersecting && !this.hasAnimated) {
              // 如果目标进入视口并且没有动画过
              this.hasAnimated = true; // 标记动画过
              observer.unobserve(entry.target); // 停止观察
            }
          });
        },
        { threshold: 0.1 }
      ); // 观察阈值，表示目标在视口的百分比
      observer.observe(this.$refs.animatedElement); // 观察目标
    },
    observeScroll() {
      const onScroll = () => {
        // scroll事件回调函数
        if (
          this.isInViewport(this.$refs.animatedElement) &&
          !this.hasAnimated
        ) {
          // 如果目标在视口并且没有动画过
          this.hasAnimated = true; // 标记动画过
          window.removeEventListener("scroll", onScroll); // 停止监听scroll事件
        }
      };
      window.addEventListener("scroll", onScroll); // 监听scroll事件
    },
    isInViewport(el) {
      // 判断目标是否在视口
      const rect = el.getBoundingClientRect();
      return rect.top < window.innerHeight && rect.bottom > 0;
    },
  },
};
</script>
  <style scoped lang='less'>
//   !!!!样式写在父组件
.text-slide-in-vue {
  p {
    text-align: center;
    width: 400px;
    height: 200px;
    background-color: goldenrod;
    margin: 0 auto;
    margin-top: 20px;
  }
}

.level-slide {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 20px;
  width: 100%;
  flex-wrap: wrap;
  height: 450px;
  overflow-y: scroll;
  p {
    text-align: center;
    width: 200px;
    height: 200px;
    background-color: blueviolet;
    margin: 0 auto;
    margin-top: 20px;
  }
}
</style>